package com.google.gwt.sample.dynatablerf.client.presenters;

import java.util.Set;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.sample.dynatablerf.client.events.CloseMaterialListEvent;
import com.google.gwt.sample.dynatablerf.client.events.CloseMaterialListEventHandler;
import com.google.gwt.sample.dynatablerf.client.events.CloseProjetoEvent;
import com.google.gwt.sample.dynatablerf.client.events.CloseServicoListEvent;
import com.google.gwt.sample.dynatablerf.client.events.CloseServicoListEventHandler;
import com.google.gwt.sample.dynatablerf.client.events.GoToProjetoStartViewEvent;
import com.google.gwt.sample.dynatablerf.client.events.MaterialSelectionChangeEvent;
import com.google.gwt.sample.dynatablerf.client.events.MaterialSelectionChangeEventHandler;
import com.google.gwt.sample.dynatablerf.client.events.ServicoSelectionChangeEvent;
import com.google.gwt.sample.dynatablerf.client.events.ServicoSelectionChangeEventHandler;
import com.google.gwt.sample.dynatablerf.client.util.GrifoConstants;
import com.google.gwt.sample.dynatablerf.shared.GrifoRequestFactory;
import com.google.gwt.sample.dynatablerf.shared.GrifoRequestFactory.ProjetoRequest;
import com.google.gwt.sample.dynatablerf.shared.GrifoSharedConvertUtil;
import com.google.gwt.sample.dynatablerf.shared.MaterialProjetoProxy;
import com.google.gwt.sample.dynatablerf.shared.MaterialProxy.TipoMaterial;
import com.google.gwt.sample.dynatablerf.shared.ProjetoProxy;
import com.google.gwt.sample.dynatablerf.shared.ServicoProjetoProxy;
import com.google.gwt.user.client.ui.TabLayoutPanel;

public class ProjetoPresenter extends
		AbstractClosableTabPresenter<ProjetoRequest> {

	public enum ValorStatus {
		NENHUM, IGUAL, AUMENTO, DIMUNICAO
	}

	public interface ProjetoDisplay extends ClosableTabDisplay {

		TabLayoutPanel getTabLayoutPanel();

		void setNumero(String numero);

		void setValorCOM(String valorCOM);

		void setValorCA(String valorCA);

		void updateValorCAIcon(ValorStatus valorStatus);

		void updateValorCOMIcon(ValorStatus valorStatus);

	}

	private ProjetoDisplay projetoDisplay;
	private ProjetoProxy projetoProxy;
	private Set<MaterialProjetoProxy> lastMaterialProjetoSelectedSet;
	private Set<ServicoProjetoProxy> lastServicoProjetoSelectedSet;
	private Double fatorCOMProjeto;
	private Double fatorCAProjeto;

	public ProjetoPresenter(ProjetoDisplay display, ProjetoProxy projetoProxy,
			EventBus eventBus, GrifoRequestFactory grifoRequestFactory) {
		super(eventBus, grifoRequestFactory);
		this.projetoDisplay = display;
		this.projetoProxy = projetoProxy;
	}

	@Override
	protected ClosableTabDisplay getClosableTabDisplay() {
		return projetoDisplay;
	}

	@Override
	protected void fireCloseWindowEvent() {
		getEventBus().fireEvent(new CloseProjetoEvent(projetoProxy));

	}

	@Override
	protected void fetch() {
		projetoDisplay.setNumero(projetoProxy.getNumero());

		calcularFatorCOM(null);

		calcularValorCA(null);

	}

	@Override
	protected void bind() {
		super.bind();

		getEventBus().addHandler(CloseMaterialListEvent.TYPE,
				new CloseMaterialListEventHandler() {

					@Override
					public void onCloseMaterialList(CloseMaterialListEvent event) {
						if (event.getProjetoProxy().equals(projetoProxy)) {
							calcularFatorCOM(null);
							calcularValorCA(lastServicoProjetoSelectedSet);
						}
					}
				});

		getEventBus().addHandler(CloseServicoListEvent.TYPE,
				new CloseServicoListEventHandler() {

					@Override
					public void onCloseServicoList(CloseServicoListEvent event) {
						if (event.getProjetoProxy().equals(projetoProxy)) {
							calcularValorCA(null);
						}
					}
				});

		getEventBus().addHandler(MaterialSelectionChangeEvent.TYPE,
				new MaterialSelectionChangeEventHandler() {

					@Override
					public void onMaterialSelectionChange(
							MaterialSelectionChangeEvent event) {
						if (event.getProjetoProxy().equals(projetoProxy)) {
							calcularFatorCOM(event.getMaterialProjetoProxySet());
							calcularValorCA(lastServicoProjetoSelectedSet);
						}
					}
				});

		getEventBus().addHandler(ServicoSelectionChangeEvent.TYPE,
				new ServicoSelectionChangeEventHandler() {

					@Override
					public void onServicoSelectionChange(
							ServicoSelectionChangeEvent event) {
						if (event.getProjetoProxy().equals(projetoProxy)) {
							calcularValorCA(event.getServicoProjetoProxySet());
						}
					}
				});

		getEventBus().fireEvent(
				new GoToProjetoStartViewEvent(this.projetoDisplay
						.getTabLayoutPanel(), projetoProxy, getEventBus()));
	}

	private void calcularFatorCOM(
			Set<MaterialProjetoProxy> materialProjetoProxySet) {
		lastMaterialProjetoSelectedSet = materialProjetoProxySet;
		double somatorioComTotal = projetoProxy.getSomatorioValorCOM();
		double somatorioUCTotal = projetoProxy.getSomatorioValorUC();
		if (materialProjetoProxySet != null) {
			for (MaterialProjetoProxy materialProjetoProxy : materialProjetoProxySet) {
				if (materialProjetoProxy.getMaterial() != null
						&& materialProjetoProxy.getMaterial().getTipoMaterial() != null) {
					TipoMaterial tipoMaterial = materialProjetoProxy
							.getMaterial().getTipoMaterial();
					if (tipoMaterial.equals(TipoMaterial.COM))
						somatorioComTotal -= materialProjetoProxy.getValor()
								* materialProjetoProxy.getQuantidade();
					else if (tipoMaterial.equals(TipoMaterial.UC))
						somatorioUCTotal -= materialProjetoProxy.getValor()
								* materialProjetoProxy.getQuantidade();
				}
			}
		}
		if (somatorioUCTotal == 0) {
			projetoDisplay.setValorCOM(GrifoConstants.INSTANCE.naoCalculavel());
			updateValorCOMIcon(null);
		} else {
			Double d = GrifoSharedConvertUtil.round(somatorioComTotal * 100
					/ somatorioUCTotal);
			projetoDisplay.setValorCOM(d + "%");
			updateValorCOMIcon(d);
		}
	}

	private void calcularValorCA(Set<ServicoProjetoProxy> servicoProjetoProxySet) {
		lastServicoProjetoSelectedSet = servicoProjetoProxySet;
		double somatorioComUCTotal = projetoProxy.getSomatorioValorCOM()
				+ projetoProxy.getSomatorioValorUC();
		if (lastMaterialProjetoSelectedSet != null) {
			for (MaterialProjetoProxy materialProjetoProxy : lastMaterialProjetoSelectedSet) {
				somatorioComUCTotal -= materialProjetoProxy.getValor()
						* materialProjetoProxy.getQuantidade();
			}
		}

		double somatorioCATotal = projetoProxy.getSomatorioValorCA();
		if (servicoProjetoProxySet != null) {
			for (ServicoProjetoProxy servicoProjetoProxy : servicoProjetoProxySet) {
				somatorioCATotal -= servicoProjetoProxy.getValor()
						* servicoProjetoProxy.getQuantidade();
			}
		}

		if (somatorioComUCTotal == 0) {
			projetoDisplay.setValorCA(GrifoConstants.INSTANCE.naoCalculavel());
			updateValorCAIcon(null);
		} else {
			Double d = GrifoSharedConvertUtil.round(somatorioCATotal * 100
					/ somatorioComUCTotal);
			projetoDisplay.setValorCA(d + "%");
			updateValorCAIcon(d);
		}
	}

	private void updateValorCAIcon(Double d) {
		if (d == null) {
			projetoDisplay.updateValorCAIcon(ValorStatus.NENHUM);
		} else if (fatorCAProjeto == null || d.equals(fatorCAProjeto)) {
			fatorCAProjeto = d;
			projetoDisplay.updateValorCAIcon(ValorStatus.IGUAL);
		} else if (d > fatorCAProjeto) {
			projetoDisplay.updateValorCAIcon(ValorStatus.AUMENTO);
		} else {
			projetoDisplay.updateValorCAIcon(ValorStatus.DIMUNICAO);
		}
	}

	private void updateValorCOMIcon(Double d) {
		if (d == null) {
			projetoDisplay.updateValorCOMIcon(ValorStatus.NENHUM);
		} else if (fatorCOMProjeto == null || d.equals(fatorCOMProjeto)) {
			fatorCOMProjeto = d;
			projetoDisplay.updateValorCOMIcon(ValorStatus.IGUAL);
		} else if (d > fatorCOMProjeto) {
			projetoDisplay.updateValorCOMIcon(ValorStatus.AUMENTO);
		} else {
			projetoDisplay.updateValorCOMIcon(ValorStatus.DIMUNICAO);
		}
	}

	@Override
	protected ProjetoRequest getRequestContext() {
		return getRequestFactory().projetoRequest();
	}

}